﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using FluffyUnderware.DevTools.Extensions;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UI;
using Yoozoo.Managers.ResourceManagerV2.Framework;
using Yoozoo.UI;
using Yoozoo.UI.YGUI;

public class YGUIPrefabOptimizer
{
    //private static Dictionary<GameObject, NestedPrefab>
    /// <summary>
    /// 只对此目录下的prefab进行优化处理
    /// </summary>
    private static string s_Prefix = "Assets/ResourcesAssets/Prefabs/UI/";
    private static PrefabStage s_PrefabStage;
    private static string s_PrefabAssetPath = string.Empty;
    private static int s_PrefabCount = 0;
    private static bool s_AllowAutoRefresh = true;

    /// <summary>
    /// localId 和 对应值 的散列表
    /// </summary>
    private static Dictionary<string, string> s_LocalIdCacheDict = new Dictionary<string, string>();
    private static Dictionary<string, string> s_LocalId2ValueDict = new Dictionary<string, string>();
    /// <summary>
    /// localId的路径 和 对应值 的散列表（stage.prefabContentsRoot 无法获取localId采用localId的路径）
    /// </summary>
    private static Dictionary<string, string> s_LocalId2PathDict   = new Dictionary<string, string>();
    private static Dictionary<string, string> s_LocalId2NestedLocalIdDict = new Dictionary<string, string>();

    private static Dictionary<int, string> s_InstanceId2LocalIdDict = new Dictionary<int, string>();
    private static Dictionary<int, string> s_InstanceId2ValueDict = new Dictionary<int, string>();
    private static Dictionary<int, string> s_InstanceId2PathDict = new Dictionary<int, string>();

    
    [MenuItem("Tools/UI/保存时清除勾选的文本和精灵")]
    static void ClearOnSave()
    {
        try
        {
            string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab", new string[] { s_Prefix });
            int totalIndex = prefabGuids.Length;
            for (int currentIndex = 569; currentIndex < totalIndex;)
            {
                string prefabGuid = prefabGuids[currentIndex];
                string prefabPath = AssetDatabase.GUIDToAssetPath(prefabGuid);
                
                string displayName = prefabPath.Replace(s_Prefix, "");
                
                currentIndex++;
                EditorUtility.DisplayProgressBar($"({currentIndex}/{totalIndex})清除勾选的文本和精灵", $"{displayName}", currentIndex / totalIndex);
                UnityEngine.Debug.LogWarning($"({currentIndex}/{totalIndex}){displayName}");
            
                Backup(prefabPath);
                OpenPrefab(prefabPath);
                SavePrefab(prefabPath);
            }
        }
        catch (Exception e)
        {
            UnityEngine.Debug.LogError(e);
        }
        EditorUtility.ClearProgressBar();
    }
    
    [InitializeOnLoadMethod]
    static void InitializeOnLoad()
    {
        // PrefabStage.prefabStageOpened += stage =>
        // {
        //     //只处理指定目录下的UI Prefab
        //     if (!stage.prefabAssetPath.StartsWith(s_Prefix))
        //     {
        //         return;
        //     }
        //     //UnityEngine.Debug.LogWarning($"----------prefabStageOpened----------{stage.prefabAssetPath}");
        //     s_PrefabStage = stage;
        //     // if (s_PrefabAssetPath.Equals(stage.prefabAssetPath)) s_PrefabCount++;
        //     // s_PrefabAssetPath = stage.prefabAssetPath;
        //     // if (s_PrefabCount >= 2) return;
        //     try
        //     {
        //         Backup(stage.prefabAssetPath);
        //     }
        //     catch (Exception e)
        //     {
        //         
        //     }
        //
        //     try
        //     {
        //         OpenPrefab(stage.prefabAssetPath, stage.prefabContentsRoot);
        //     }
        //     catch (Exception e)
        //     {
        //         
        //     }
        // };
        //
        // PrefabStage.prefabStageClosing += stage =>
        // {
        //     try
        //     {
        //         s_PrefabStage = stage;
        //         //只处理指定目录下的UI Prefab
        //         if (!stage.prefabAssetPath.StartsWith(s_Prefix))
        //         {
        //             return;
        //         }
        //         SavePrefab(stage.prefabAssetPath);
        //     }
        //     catch (Exception e)
        //     {
        //         
        //     }
        //     
        //     s_PrefabStage = null;
        //     s_PrefabAssetPath = string.Empty;
        //     s_PrefabCount = 0;
        // };

        // PrefabStage.prefabSaving += o =>
        // {
        //     UnityEngine.Debug.LogWarning($"----------prefabSaving----------{o.name}");
        // };
        //
        // PrefabStage.prefabSaved += o =>
        // {
        //     UnityEngine.Debug.LogWarning($"----------prefabSaved----------{o.name}");
        // };
    }
    
    

    public static bool OpenPrefab(string prefabAssetPath, GameObject prefabContentsRoot = null)
    {
        //localId 和 对应值 的散列表
        s_LocalIdCacheDict.Clear();
        //
        s_LocalId2ValueDict.Clear();
        //localId的路径 和 对应值 的散列表（stage.prefabContentsRoot 无法获取localId采用localId的路径）
        s_LocalId2PathDict.Clear();
        s_LocalId2NestedLocalIdDict.Clear();
        //
        s_InstanceId2LocalIdDict.Clear();
        s_InstanceId2ValueDict.Clear();
        s_InstanceId2PathDict.Clear();
        //**********
        //第一步 读取嵌套prefab的缓存数据
        //**********
        //尝试获取 该prefab中嵌套的所有prefab的缓存数据
        GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabAssetPath);
        Dictionary<GameObject, NestedPrefab> nestedPrefabDict = new Dictionary<GameObject, NestedPrefab>();
        FindNestedPrefab(prefab.transform, nestedPrefabDict);
        //成功获取 该prefab中嵌套的所有prefab的缓存
        
        
        
        
        //**********
        //第二步 读取当前prefab的缓存数据
        //**********
        string localId = string.Empty;
        string value   = string.Empty;
        string assetGuid = AssetDatabase.AssetPathToGUID(prefabAssetPath);
        string prefabPath = $"{workingPath}/{assetGuid}";
        //当前UI Prefab 不存在缓存数据 则不处理
        if (File.Exists(prefabPath))
        {
            //读取缓存数据
            string cacheData = File.ReadAllText(prefabPath);
            //每条缓存数据以:%EOF%\r\n为结束符
            string[] lines = cacheData.Split(new string[]{"%%EOF%%\r\n"}, StringSplitOptions.RemoveEmptyEntries);
            //分号的索引值
            int semicolonBeginIndex = 0;
            int semicolonSecondIndex = 0;
            foreach (var line in lines)
            {
                semicolonBeginIndex = line.IndexOf(":");
                semicolonSecondIndex = line.IndexOf(":", semicolonBeginIndex + 1);
                //根据第一个分号和最后一个分号 切为3部分
                //第一部分是path 不使用 
                //第二部分是localId
                //第三部分是value
                //path = line.Substring(0, semicolonBeginIndex);
                localId = line.Substring(semicolonBeginIndex + 1, semicolonSecondIndex - semicolonBeginIndex - 1);
                value   = line.Substring(semicolonSecondIndex + 1);
                s_LocalIdCacheDict.Add(localId, value);
            }
        }
        
        
        //**********
        //第三步 读取当前prefab的数据
        //**********
        //prefab中的组件
        //根据prefab中的组件来获取路径和值的映射关系
        //已经有localId和值的映射关系 为何还要获取路径和值的映射关系呢？
        //因为我们从打开的实例对象中(stage.prefabContentsRoot)无法获取localId 所以
        //我们采用prefab中localId和其路径相对应的关系 可以知道路径肯定是最新的 可以用在实例对象中
        //然后设置实例对象(stage.prefabContentsRoot)中路径的值
        List<Component> components = new List<Component>();
        prefab.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
        prefab.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
        foreach (var component in components)
        {
            //获取相应组件的localId
            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component, out string guid, out long fileId);
            localId = fileId.ToString();
            
            
            int instanceId = component.GetInstanceID();
            //该组件是否存在缓存中的值
            if (s_LocalIdCacheDict.TryGetValue(localId, out var cachedValue))
            {
                if (!s_InstanceId2ValueDict.ContainsKey(instanceId))
                {
                    s_InstanceId2ValueDict.Add(instanceId, cachedValue);
                    s_InstanceId2PathDict.Add(instanceId, component.getFullName());
                }
            }

            if (s_InstanceId2ValueDict.TryGetValue(instanceId, out cachedValue))
            {
                if (!string.IsNullOrEmpty(cachedValue))
                {
                    SetComponentValue(component, cachedValue);
                }
            }
            
            //Prefab中组件的localId和路径的映射关系（仅方便测试使用）
            s_LocalId2PathDict.Add(localId, component.getFullName());
            
            
            //用于计算当前Prefab中各组件的localId和嵌套对象的Prefab中相应组件的localId的映射关系
            //获取相应组件的localId
            Component sourceComponent = PrefabUtility.GetCorrespondingObjectFromSource(component);
            if (sourceComponent == null)
            {
                sourceComponent = component;
            }
            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(sourceComponent, out var nestedGuid, out long nestedFileId);
            string nestedLocalId = nestedFileId.ToString();
            
            //父对象localId 和 嵌套Prefab中相应对象localId的映射关系
            s_LocalId2NestedLocalIdDict.Add(localId, nestedLocalId);
        }
        
        //PrefabUtility.SavePrefabAsset(prefab);
        //EditorUtility.SetDirty(prefab);
        
        var path2LocalIdDict = s_LocalId2PathDict;
        
        
        
        // //当前打开的prefab的实例对象
        // GameObject gameObject = stage.prefabContentsRoot;
        // string rootPath   = string.Empty;
        // List<Component> components = new List<Component>();
        // gameObject.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
        // gameObject.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
        // foreach (var component in components)
        // {
        //     bool isPart = PrefabUtility.IsPartOfPrefabInstance(component);
        //     //无法从实例对象获取localId
        //     //AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component.GetInstanceID(), out string guid, out long fileId);
        //     Component sourceComponent1 = PrefabUtility.GetCorrespondingObjectFromOriginalSource(component);
        //     Component sourceComponent = PrefabUtility.GetCorrespondingObjectFromSource(component);
        //     if (sourceComponent == null)
        //     {
        //         sourceComponent = PrefabUtility.GetCorrespondingObjectFromSourceAtPath(component, stage.prefabAssetPath);
        //     }
        //     if (sourceComponent == null) sourceComponent = component;
        //     AssetDatabase.TryGetGUIDAndLocalFileIdentifier(sourceComponent.GetInstanceID(), out var guid, out long fileId);
        //     string localId = fileId.ToString();
        // }
        if (prefabContentsRoot == null)
        {
            return false;
        }
        //当前打开的prefab的实例对象
        GameObject gameObject = prefabContentsRoot;
        string rootPath   = string.Empty;
        components.Clear();
        gameObject.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
        gameObject.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
        foreach (var component in components)
        {
            Transform current = component.transform;
            int childCount = 0;
            List<int> indexes = new List<int>();
            while (current.parent != null)
            {
                childCount = current.parent.childCount;
                for (int index = 0; index < childCount; index++)
                {
                    if (current.parent.GetChild(index) == current)
                    {
                        indexes.Add(index);
                        current = current.parent;
                        break;
                    }
                }
            }
            //移除最后一个 最后一个是Canvas(Environment)
            indexes.RemoveAt(indexes.Count - 1);
            indexes.Reverse();
            current = prefab.transform;
            foreach (var index in indexes)
            {
                current = current.GetChild(index);
            }

            Component sourceComponent = current.GetComponent(component.GetType());
            string sourceValue = GetComponentValue(sourceComponent);
            SetComponentValue(component, sourceValue);
        }
        
        return true;
    }
    public static void SavePrefab(string prefabAssetPath)
    {
        StringBuilder sBuilder = new StringBuilder();
        GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabAssetPath);
        string line = string.Empty;
        bool isCacheChanged = false;
        string localId = string.Empty;
        //当前最新的id映射
        Dictionary<string, string> localIdDict = new Dictionary<string, string>();
        // List<Component> components = new List<Component>();
        // prefab.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
        // prefab.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
        // foreach (var component in components)
        // {
        // }
        s_InstanceId2LocalIdDict.Clear();
        s_InstanceId2ValueDict.Clear();
        s_InstanceId2PathDict.Clear();
        //读取嵌套的Prefab 获取只有在嵌套Prefab中使用而没有被当前Prefab覆盖的instanceId的属性列表
        Dictionary<GameObject, NestedPrefab> nestedPrefabDict = new Dictionary<GameObject, NestedPrefab>();
        FindNestedPrefab(prefab.transform, nestedPrefabDict);
        
        
        
        //处理YText
        string componentValue = string.Empty;
        YText[] texts = prefab.GetComponentsInChildren<YText>(true);
        foreach (var component in texts)
        {
            //勾选 保存时清除文本选项
            if (component.clearOnSave)
            {
                int instanceId = component.GetInstanceID();
                //被嵌套的Prefab所处理的属性 不需要被当前Prefab处理
                if (s_InstanceId2PathDict.ContainsKey(instanceId))
                {
                    continue;
                }
                
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component, out string guid, out long fileId);
                localId = fileId.ToString();
                componentValue = GetComponentValue(component);
                sBuilder.Append($"{component.getFullName()}:{localId}:{componentValue}%%EOF%%\r\n");
                //最新的键值对
                localIdDict.Add(localId, componentValue);
                //清除文本
                component.text = String.Empty;
            }
        }
        //处理YImage
        YImage[] images = prefab.GetComponentsInChildren<YImage>(true);
        foreach (var component in images)
        {
            //勾选 保存时清除精灵选项
            if (component.clearOnSave)
            {
                int instanceId = component.GetInstanceID();
                //被嵌套的Prefab所处理的属性 不需要被当前Prefab处理
                if (s_InstanceId2PathDict.ContainsKey(instanceId))
                {
                    continue;
                }
                
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component, out string guid, out long fileId);
                localId = fileId.ToString();
                componentValue = GetComponentValue(component);
                sBuilder.Append($"{component.getFullName()}:{localId}:{componentValue}%%EOF%%\r\n");
                //最新的键值对
                localIdDict.Add(localId, componentValue);
                //清除精灵
                component.sprite = null;
            }
        }
        
        
        PrefabUtility.SavePrefabAsset(prefab);
        
        
        //如果缓存中的对象的数量和prefab中的数量不一致 则需要更新
        if (s_LocalIdCacheDict.Count != localIdDict.Count)
        {
            isCacheChanged = true;
        }
        else
        {
            foreach (var kv in localIdDict)
            {
                if (s_LocalIdCacheDict.TryGetValue(kv.Key, out var cacheValue))
                {
                    if (kv.Value == cacheValue)
                    {
                        //缓存中存在该数据 则过滤掉相同的值 用于判断最后剩余的数量
                        s_LocalIdCacheDict.Remove(kv.Key);
                    }
                    else
                    {
                        //和缓存中的值不一致 则表示数据发生了变化
                        isCacheChanged = true;
                        break;
                    }
                }
                else
                {
                    //在缓存中不存在该键值 表示数据发生了变化
                    isCacheChanged = true;
                    break;
                }
            }
            
            //过滤后 缓存中还存在多余的键值 表示数据发生了变化
            if (s_LocalIdCacheDict.Count > 0)
            {
                isCacheChanged = true;
            }
        }
        
        if (isCacheChanged)
        {
            string assetGuid = AssetDatabase.AssetPathToGUID(prefabAssetPath);
            string prefabPath = $"{workingPath}/{assetGuid}";
            File.WriteAllText(prefabPath, sBuilder.ToString());
        }
        
        //UnityEngine.Debug.LogWarning($"-----prefabStageClosing-----{prefabAssetPath} cacheChanged:{isCacheChanged}");
    }

    static int SortLayoutList(Component x, Component y)
    {
        Transform t1 = x.transform;
        Transform t2 = y.transform;

        return ParentCount(t1) - ParentCount(t2);
    }
    static int ParentCount(Transform child)
    {
        if (child == null)
            return 0;

        var parent = child.parent;
        int count = 0;
        while (parent != null)
        {
            count++;
            parent = parent.parent;
        }
        return count;
    }
    
    /// <summary>
    /// 找到嵌套的Prefab
    /// </summary>
    /// <param name="transform"></param>
    /// <param name="nestedPrefabDict"></param>
    static void FindNestedPrefab(Transform transform, Dictionary<GameObject, NestedPrefab> nestedPrefabDict)
    {
        List<Component> components = new List<Component>();
        transform.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
        transform.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
        components.Sort(SortLayoutList);
        foreach (var component in components)
        {
            GameObject root = PrefabUtility.GetNearestPrefabInstanceRoot(component);
            if (root != null && !nestedPrefabDict.ContainsKey(root))
            {
                NestedPrefab nestedPrefab    = new NestedPrefab();
                nestedPrefab.gameObject      = root;
                nestedPrefab.assetPath       = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(root);
                nestedPrefab.modifications   = PrefabUtility.GetPropertyModifications(root);
                nestedPrefab.objectOverrides = PrefabUtility.GetObjectOverrides(root);
                nestedPrefab.Read();
                nestedPrefabDict.Add(root, nestedPrefab);
            }
        }

        var dict = nestedPrefabDict;
        // int childCount = transform.childCount;
        // GameObject root = null;
        // Transform child = null;
        // for (int i = 0; i < childCount; ++i)
        // {
        //     child = transform.GetChild(i);
        //     root = PrefabUtility.GetNearestPrefabInstanceRoot(child);
        //     if (root != null && !nestedPrefabDict.ContainsKey(root))
        //     {
        //         NestedPrefab nestedPrefab    = new NestedPrefab();
        //         nestedPrefab.gameObject      = root;
        //         nestedPrefab.assetPath       = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(root);
        //         nestedPrefab.modifications   = PrefabUtility.GetPropertyModifications(root);
        //         nestedPrefab.objectOverrides = PrefabUtility.GetObjectOverrides(root);
        //         nestedPrefab.Read();
        //         nestedPrefabDict.Add(root, nestedPrefab);
        //     }
        //     FindNestedPrefab(child, nestedPrefabDict);
        // }
    }
    private static void SetComponentValue(Component component, string value)
    {
        //设置prefab中组件的值 用于打开prefab没有任何改变 在关闭的情况 以保证流程正常
        string typeName = component.GetType().Name;
        switch (typeName)
        {
            case "YText":
                (component as YText).text = value;
                break;
            case "YImage":
                (component as YImage).sprite = AssetDatabase.LoadAssetAtPath<Sprite>(AssetDatabase.GUIDToAssetPath(value));
                break;
        }
    }
    private static string GetComponentValue(Component component)
    {
        string value = string.Empty;
        string typeName = component.GetType().Name;
        switch (typeName)
        {
            case "YText":
                value = (component as YText).text;
                break;
            case "YImage":
                value = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath((component as YImage).sprite));
                break;
        }

        return value;
    }




    /// <summary>
    /// backup
    /// </summary>
    static void Backup(string prefabAssetPath)
    {
        string assetGuid = AssetDatabase.AssetPathToGUID(prefabAssetPath);
        string path = $"{backupPath}/{assetGuid}";
        if (!File.Exists(path))
        {
            GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabAssetPath);
            List<Component> components = new List<Component>();
            StringBuilder sBuilder = new StringBuilder();
            prefab.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
            prefab.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
            foreach (var component in components)
            {
                //获取相应组件的localId
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component, out string guid, out long fileId);
                string localId = fileId.ToString();

                string componentValue = GetComponentValue(component);
                sBuilder.Append($"{component.getFullName()}:{localId}:{componentValue}%%EOF%%\r\n");
            }
                    
            File.WriteAllText(path, sBuilder.ToString());
        }
    }
    
    static string cacheRootPath
    {
        get
        {
            string cachePath    = Utility.Path.GetRegularPath($"{Environment.CurrentDirectory}/Caches/UI");
            //UnityEngine.Debug.LogWarning($"----------cachePath----------{cachePath}");
            string cacheFolder = Path.GetDirectoryName(cachePath);
            if (Directory.Exists(cacheFolder) == false)
            {
                Directory.CreateDirectory(cacheFolder);
            }
            
            return cachePath;
        }
    }
    static string backupPath
    {
        get
        {
            string backupPath = $"{cacheRootPath}/Backup";
            string backupFolder = Path.GetDirectoryName(backupPath);
            if (Directory.Exists(backupFolder) == false)
            {
                Directory.CreateDirectory(backupFolder);
            }
            
            return backupPath;
        }
    }
    static string workingPath
    {
        get
        {
            string workingPath = $"{cacheRootPath}/Working";
            string workingFolder = Path.GetDirectoryName(workingPath);
            if (Directory.Exists(workingFolder) == false)
            {
                Directory.CreateDirectory(workingFolder);
            }
            
            return workingPath;
        }
    }
    

    public class NestedPrefab
    {
        /// <summary>
        /// 应用于预制件实例的所有修改（与父预制件相比）
        /// </summary>
        private PropertyModification[] m_Modifications;
        private List<ObjectOverride> m_ObjectOverrides;
        public GameObject gameObject { get; set; }
        public string assetPath { get; set; }
        /// <summary>
        /// 应用于预制件实例的所有修改（与父预制件相比）
        /// </summary>
        public PropertyModification[] modifications
        {
            get => m_Modifications;
            set
            {
                List<PropertyModification> list = new List<PropertyModification>();
                foreach (var modification in value)
                {
                    if (//modification.propertyPath == "m_Name" ||
                        modification.propertyPath == "m_Text" ||
                        modification.propertyPath == "m_Sprite")
                    {
                        list.Add(modification);
                    }
                }
                m_Modifications = list.ToArray();
            }
        }

        public List<ObjectOverride> objectOverrides
        {
            get => m_ObjectOverrides;
            set => m_ObjectOverrides = value;
        }

        public List<Component> components { get; set; }

        /// <summary>
        /// 该嵌套Prefab缓存的属性值
        /// </summary>
        public Dictionary<string, string> localIdCacheDict { get; set; } = new Dictionary<string, string>();
        /// <summary>
        /// 该嵌套Prefab被其父Prefab使用的属性值(缓存的属性值中 剔除 父Prefab修改覆盖的属性值)
        /// </summary>
        public Dictionary<string, string> localIdDict { get; set; } = new Dictionary<string, string>();

        public Dictionary<string, int> localId2InstanceIdDict { get; set; } = new Dictionary<string, int>();

        public Dictionary<string, string> localId2PathDict { get; set; } = new Dictionary<string, string>();

        public void Read()
        {
            string assetGuid = AssetDatabase.AssetPathToGUID(assetPath);
            string cachePath = $"{workingPath}/{assetGuid}";
            //当前UI Prefab 不存在缓存数据 则不处理
            if (File.Exists(cachePath) == false)
            {
                return;
            }
            //读取缓存数据
            string cacheData = File.ReadAllText(cachePath);
            //每条缓存数据以%%EOF%%\r\n为结束符
            string[] lines = cacheData.Split(new string[]{"%%EOF%%\r\n"}, StringSplitOptions.RemoveEmptyEntries);
            string localId = string.Empty;
            string value   = string.Empty;
            //分号的索引值
            int semicolonBeginIndex = 0;
            int semicolonSecondIndex = 0;
            foreach (var line in lines)
            {
                semicolonBeginIndex = line.IndexOf(":");
                semicolonSecondIndex = line.IndexOf(":", semicolonBeginIndex + 1);
                //根据第一个分号和最后一个分号 切为3部分
                //第一部分是path 不使用 
                //第二部分是localId
                //第三部分是value
                //path = line.Substring(0, semicolonBeginIndex);
                localId = line.Substring(semicolonBeginIndex + 1, semicolonSecondIndex - semicolonBeginIndex - 1);
                value   = line.Substring(semicolonSecondIndex + 1);
                localIdCacheDict.Add(localId, value);
                localIdDict.Add(localId, value);
            }
            
            //嵌套的prefab 获取相应组件的localId
            //GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
            // List<Component> components = new List<Component>();
            // prefab.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
            // prefab.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
            // foreach (var component in components)
            // {
            //     //获取相应组件的localId
            //     AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component, out string guid, out long fileId);
            //     localId = fileId.ToString();
            //     InstanceId2LocalIdDict.Add(component.GetInstanceID(), localId);
            // }
            //获取嵌套的Prefab的实例的映射关系
            components = new List<Component>();
            gameObject.GetComponentsInChildren<YText>(true).ForEach(element=>components.Add(element));
            gameObject.GetComponentsInChildren<YImage>(true).ForEach(element=>components.Add(element));
            foreach (var component in components)
            {
                //实例无法获取相应组件的localId
                //AssetDatabase.TryGetGUIDAndLocalFileIdentifier(component, out string guid, out long fileId);
                //localId = fileId.ToString();
                Component sourceComponent = PrefabUtility.GetCorrespondingObjectFromSource(component);
                if (sourceComponent == null)
                {
                    sourceComponent = component;
                }
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier(sourceComponent, out var guid, out long fileId);
                localId = fileId.ToString();
                
                if (localIdCacheDict.TryGetValue(localId, out var cachedValue))
                {
                    
                }
                
                int instanceId = component.GetInstanceID();
                localId2InstanceIdDict.Add(localId, instanceId);
                localId2PathDict.Add(localId, sourceComponent.getFullName());

                
                string fullName = component.getFullName();
                if (!s_InstanceId2ValueDict.ContainsKey(instanceId))
                {
                    s_InstanceId2ValueDict.Add(instanceId, cachedValue);
                    s_InstanceId2PathDict.Add(instanceId, fullName);
                }
                else
                {
                    //UnityEngine.Debug.LogWarning($"重复的instanceId:{instanceId}  tree:{fullName}");
                    s_InstanceId2ValueDict[instanceId] = cachedValue;
                    s_InstanceId2PathDict[instanceId] = fullName;
                }
                
            }
            
            //新的预制体中被修改的实例对象
            //该对象已被新的预制体覆盖
            //应用于预制件实例的所有修改（与父预制件相比）
            foreach (var modification in modifications)
            {
                //该嵌套Prefab在父Prefab中被覆盖的属性
                //如果存在覆盖属性 则不在读取该嵌套Prefab中缓存的属性
                if (modification.target == null)
                {
                    continue;
                }
                Component target = modification.target as Component;
                Component sourceComponent = PrefabUtility.GetCorrespondingObjectFromSource(target);
                if (sourceComponent == null)
                {
                    sourceComponent = target;
                }
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier(sourceComponent, out var guid, out long fileId);
                localId = fileId.ToString();
                
                //注意 如果嵌套Prefab缓存的原始值和当前的值一致 则表示该属性没有被覆盖
                if (localIdCacheDict.TryGetValue(localId, out var cachedValue))
                {
                    if (modification.objectReference != null)
                    {
                        AssetDatabase.TryGetGUIDAndLocalFileIdentifier(modification.objectReference, out var referenceGuid, out long referenceFileId);
                        modification.value = referenceGuid;
                    }
                    if (cachedValue.Equals(modification.value))
                    {
                        continue;
                    }
                }
                
                //如果该属性被新的Prefab覆盖 那么需要将其移除 在外部设置的时候用外部的值
                //此处的逻辑是 如果存在嵌套属性值优先使用 没有嵌套属性值则使用新的Prefab的值
                //如果被新的Prefab覆盖 将此处移除 那么就会直接使用新的Prefab的值
                if (localId2InstanceIdDict.TryGetValue(localId, out var instanceId))
                {
                    s_InstanceId2ValueDict.Remove(instanceId);
                    s_InstanceId2PathDict.Remove(instanceId);
                }
            }
            
        }
    }


    public void Obsolete(string prefabAssetPath)
    {
        GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabAssetPath);
        string localId = string.Empty;
        string value   = string.Empty;
        string rootPath = string.Empty;
        //prefab中的组件
        //根据prefab中的组件来获取路径和值的映射关系
        //已经有localId和值的映射关系 为何还要获取路径和值的映射关系呢？
        //因为我们从打开的实例对象中(stage.prefabContentsRoot)无法获取localId 所以
        //我们采用prefab中localId和其路径相对应的关系 可以知道路径肯定是最新的 可以用在实例对象中
        //然后设置实例对象(stage.prefabContentsRoot)中路径的值
        YText[] texts = prefab.GetComponentsInChildren<YText>(true);
        foreach (var text in texts)
        {
            //获取相应组件的localId
            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(text, out string guid, out long fileId);
            localId = fileId.ToString();
            //获取相应组件的路径 该localId对应的最新路径
            rootPath = text.getFullName();
            //生成路径映射值 用于 stage.prefabContentsRoot 因为它没发获取localId而采用路径
            s_LocalId2PathDict.Add(localId, rootPath);
            
            //该组件是否存在缓存中的值
            if (s_LocalIdCacheDict.TryGetValue(localId, out var content))
            {
                //设置prefab中组件的值 用于打开prefab没有任何改变 在关闭的情况 以保证流程正常
                text.text = content;
            }
        }
        
        
        //处理YImage
        YImage[] images = prefab.GetComponentsInChildren<YImage>(true);
        foreach (var image in images)
        {
            //获取相应组件的localId
            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(image, out string guid, out long fileId);
            localId = fileId.ToString();
            //获取相应组件的路径 该localId对应的最新路径
            rootPath = image.getFullName();
            //生成路径映射值 用于 stage.prefabContentsRoot 因为它没发获取localId而采用路径
            s_LocalId2PathDict.Add(localId, rootPath);
            
            //该组件是否存在缓存中的值
            if (s_LocalIdCacheDict.TryGetValue(localId, out var spriteGuid))
            {
                //设置prefab中组件的值 用于打开prefab没有任何改变 在关闭的情况 以保证流程正常
                image.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(AssetDatabase.GUIDToAssetPath(spriteGuid));
            }
        }
    }
}
